package com.beiding.workordersystem.main.service.impl;

import com.beiding.workordersystem.common.service.BaseService;
import com.beiding.workordersystem.common.standard.E;
import com.beiding.workordersystem.common.utils.QueryUtils;
import com.beiding.workordersystem.common.utils.TreeUtils;
import com.beiding.workordersystem.main.dao.OptionDao;
import com.beiding.workordersystem.main.dao.OptionItemDao;
import com.beiding.workordersystem.main.entity.Option;
import com.beiding.workordersystem.main.entity.OptionItem;
import com.beiding.workordersystem.main.option.TreeAble;
import com.beiding.workordersystem.main.service.OptionService;
import com.beiding.workordersystem.main.utils.Json;
import com.beiding.workordersystem.main.utils.OptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class OptionServiceImpl extends BaseService implements OptionService {

    @Autowired
    private OptionDao optionDao;
    @Autowired
    private OptionItemDao optionItemDao;

    @Override
    @Transactional
    public void save(Option option) {

        if (option.getId() == null) {

            //生成id
            option.setId(createId());

            //判断是否是 TreeAble 的
            Class<?>[] classes = option.getType().getInterfaces();
            boolean it = false;
            for (Class<?> aClass : classes) {
                if (aClass == TreeAble.class) {
                    it = true;
                    break;
                }
            }

            //如果是树状的
            if (it) {

                //首先获取pid
                Object pid = option.getPid();
                E.notNull(pid,"必须给定pid字段");
                int h;
                if (pid.equals(option.getTypeName())) {
                    h = 1;
                } else {
                    Option one = optionDao.selectOne(QueryUtils.getQuery(Option.class).eq(Option::getId, pid));
                    E.notNull(one, "父节点不存在");
                    TreeAble treeAble = (TreeAble) OptionUtils.optionToBean(one);
                    h = treeAble.getHierarchy() + 1;
                }
                option.setHierarchy(h);
            }

            //将鄋的item进行插入
            List<OptionItem> items = option.getItems();
            for (OptionItem item : items) {
                fillId(item);
                item.setOptionId(option.getId());
                optionItemDao.insert(item);
            }

            //插入元素
            optionDao.insert(option);
        } else {

            List<OptionItem> selectList = optionItemDao.selectList(QueryUtils.getQuery(OptionItem.class).eq(OptionItem::getOptionId, option.getId()));

            Map<String, OptionItem> itemMap = new HashMap<>();

            for (OptionItem item : selectList) {
                itemMap.put(item.getTheKey(), item);
            }

            List<OptionItem> items = option.getItems();
            for (OptionItem item : items) {
                OptionItem optionItem = itemMap.get(item.getTheKey());
                if (optionItem == null) {
                    fillId(item);
                    item.setOptionId(option.getId());
                    optionItemDao.insert(item);
                } else {
                    optionItem.setValue(item.getValue());
                    optionItemDao.updateById(optionItem);
                }
            }
        }

    }

    //找到给定类型的
    private Option findTreeRoot(Class<?> type) {
        Option option = optionDao.selectOne(QueryUtils.getQuery(Option.class).eq(Option::getId, type.getName()).eq(Option::getTypeName,type.getName()));
        fillItem(option);
        return option;
    }

    private void fillItem(Option option) {
        if (option != null) {
            try {
                List<OptionItem> items = optionItemDao.selectList(QueryUtils.getQuery(OptionItem.class).eq(OptionItem::getOptionId, option.getId()));
                option.setItems(items);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }
    }

    @Override
    public Object tree(Class<? extends TreeAble> aClass) {

        Option root = findTreeRoot(aClass);

        //插入根节点
        if (root == null) {
            root = new Option();
            root.setTypeName(aClass.getName());
            root.setId(root.getTypeName());
            root.setHierarchy(0);
            root.setType(aClass);
            optionDao.insert(root);
        }

        TreeAble r = (TreeAble) OptionUtils.optionToBean(root);
        TreeUtils.fillChildren(r, "children", o -> {
            List<Option> options = optionDao.selectList(QueryUtils.getQuery(Option.class).eq(Option::getPid, o.getId()));
            for (Option option : options) {
                fillItem(option);
            }
            return (List) OptionUtils.optionsToBeans(options);
        });
        return r;
    }

    @Override
    @Transactional
    public void delete(String[] ids) {
        for (String id : ids) {
            optionItemDao.delete(QueryUtils.getQuery(OptionItem.class).eq(OptionItem::getOptionId, id));
            optionDao.deleteById(id);

            try {
                List<OptionItem> items = optionItemDao.selectList(QueryUtils.getQuery(OptionItem.class).eq(OptionItem::getTheKey, "pid").eq(OptionItem::getValueString, Json.stringify(id)));

                if (items.size() > 0) {

                    List<Option> options = optionDao.selectList(QueryUtils.getQuery(Option.class).in(Option::getId, items.stream().map(OptionItem::getOptionId).collect(Collectors.toList())));
                    if (options.size() > 0) {
                        String[] idN = new String[options.size()];
                        for (int i = 0; i < options.size(); i++) {
                            idN[i] = options.get(i).getId();
                        }
                        delete(idN);

                    }
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public List list(Class<?> aClass) {
        List<Option> options = optionDao.selectList(QueryUtils.getQuery(Option.class).eq(Option::getTypeName, aClass.getName()));
        for (Option option : options) {
            List<OptionItem> list = optionItemDao.selectList(QueryUtils.getQuery(OptionItem.class).eq(OptionItem::getOptionId, option.getId()));
            option.setItems(list);
        }
        return OptionUtils.optionsToBeans(options);
    }

}
